package com.apes.fn.scm.internal.help.service.voucher.retail;

import com.apes.fn.scm.retailOrder.model.RetailOrderDiscount;
import com.apes.fn.scm.retailReturn.RetailReturn;
import com.apes.fn.scm.retailReturn.RetailReturnItem;
import com.apes.fn.server.servicePlan.model.ServicePlanItem;
import com.apes.fn.server.servicePlan.repository.ServicePlanItemRepository;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.util.DateUtil;
import com.apes.framework.util.MapUtil;
import com.apes.framework.util.ReflectUtil;
import com.apes.scm.account.account.model.AccountingMethod;
import com.apes.scm.account.account.model.InventoryBatch;
import com.apes.scm.account.account.model.InventoryMode;
import com.apes.scm.account.account.service.InventoryService;
import com.apes.scm.masterdata.finance.model.CrossIC;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.voucher.model.Voucher;
import com.apes.scm.voucher.model.VoucherInventory;
import com.apes.scm.voucher.model.VoucherItem;
import com.apes.scm.voucher.repository.VoucherInventoryRepository;
import com.apes.scm.voucher.repository.VoucherRepository;
import com.apes.scm.voucher.service.BusinessType;
import com.apes.scm.voucher.service.VoucherType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

import static com.apes.framework.util.DateUtil.SHOW_DATE_FORMAT;

/**
 * 退异业合作账目逻辑
 * 这里只退挂账部分，服务部分由公共部分处理
 *
 * @Author wuq
 * @Date 2021-10-13
 */
@Service
public class CrossICReturnVoucherService extends DomainService {

    @Autowired
    private ServicePlanItemRepository servicePlanItemRepository;
    @Autowired
    private VoucherRepository voucherRepository;
    @Autowired
    private InventoryService inventoryService;

    public void process(RetailReturn retailReturn) {
        // 异业正向流程是一条一条的写的凭证，所以这里就循环写
        retailReturn.getSaleItems().forEach(
                retailReturnItem -> {
                    // 查询明细中是否存在异业合作部分
                    long count = retailReturnItem.getRetailOrderItem().getRetailDiscounts().stream().filter(RetailOrderDiscount::checkIsCrossIC).count();
                    if (count > 0) {
                        returnCrossIC(retailReturn, retailReturnItem);
                    }
                });
    }

    private void returnCrossIC(RetailReturn retailReturn, RetailReturnItem retailReturnItem) {
        // 获取服务方案明细
        String servicePlanItemId = retailReturnItem.getRetailOrderItem().getOriginnumber();
        ServicePlanItem servicePlanItem = servicePlanItemRepository.findOne(servicePlanItemId);

        // 判断异业是否跨公司
        CrossIC crossIC = servicePlanItem.getCrossIC();
        if (Objects.equals(crossIC.getCompany().getId(), retailReturn.getCompany().getId())) {
            // 直接找异业合作方
            returnProcess(retailReturn, retailReturnItem, servicePlanItem);
        } else {
            // 跨公司异业采购

            // 对于系统上线之前（2022.03.01）的零售单产生的异业不做处理
            Date systemSwitchedDate = DateUtil.parse("2022-03-01", SHOW_DATE_FORMAT);
            if (DateUtil.dateCompare(systemSwitchedDate, retailReturn.getSaleOrder().getCreateDate()) > 0) return;

            returnCrossProcess(retailReturn, retailReturnItem, servicePlanItem);
        }
    }

    private void returnProcess(RetailReturn retailReturn, RetailReturnItem retailReturnItem, ServicePlanItem servicePlanItem) {
        // 第一步：退对异业公司的销售
        // 找原销售凭证
        PartyRole crossIC = servicePlanItem.getCrossIC().getPartner().getParty().getPatyRoleByType("Customer");     // 异业公司
        Voucher originSaleVoucher = voucherRepository.findSaleVoucherByCompanyAndItemOrigin(retailReturn.getCompany(), crossIC, servicePlanItem.getId());
        Optional.ofNullable(originSaleVoucher).orElseThrow(() -> new RuntimeException("异业合作退回时，没有找到原销售凭证！"));
        returnSaleVoucher(retailReturn, retailReturnItem, originSaleVoucher, false);

        // 第二步：门店0元采购返厂
        returnPurchaseVoucher(retailReturn.getCompany(), retailReturn, retailReturnItem, originSaleVoucher);
    }

    private void returnCrossProcess(RetailReturn retailReturn, RetailReturnItem retailReturnItem, ServicePlanItem servicePlanItem) {
        // 第一步：退对异业公司的销售
        // 找原销售凭证
        PartyRole crossIC = servicePlanItem.getCrossIC().getPartner().getParty().getPatyRoleByType("Customer");     // 异业公司
        PartyRole company = servicePlanItem.getCrossIC().getCompany();     // 异业合作方
        Voucher originCrossICSaleVoucher = voucherRepository.findSaleVoucherByCompanyAndItemOrigin(company, crossIC, servicePlanItem.getId());
        Optional.ofNullable(originCrossICSaleVoucher).orElseThrow(() -> new RuntimeException("异业合作跨公司退回时，没有找到原销售凭证！"));
        returnSaleVoucher(retailReturn, retailReturnItem, originCrossICSaleVoucher, true);

        // 第二步：退异业合作公司对门店的采购
        returnPurchaseVoucher(retailReturn.getCompany(), retailReturn, retailReturnItem, originCrossICSaleVoucher);

        // 第三步：退门店对异业合作公司的销售
        // 找原销售凭证
        PartyRole partner = company.getParty().getPartyRoleByType("Customer");
        Voucher originStoreVoucher = voucherRepository.findSaleVoucherByCompanyAndItemOrigin(retailReturn.getCompany(), partner, servicePlanItem.getId());
        returnSaleVoucher(retailReturn, retailReturnItem, originStoreVoucher, false);

        // 第四步：退门店0元采购
        returnPurchaseVoucher(retailReturn.getCompany(), retailReturn, retailReturnItem, originStoreVoucher);
    }

    /**
     * 构建销售退回凭证
     *
     * @param retailReturn      零售退货主表
     * @param retailReturnItem  零售退货明细
     * @param originSaleVoucher 原销售凭证
     * @param isSaleCrossIC     是否为对异业合作公司的销售  true 表示对异业合作方的销售退回， false 为直接对异业合作方的销售
     */
    private void returnSaleVoucher(RetailReturn retailReturn, RetailReturnItem retailReturnItem, Voucher originSaleVoucher, boolean isSaleCrossIC) {
        Voucher voucher = new Voucher();
        // 销售退回必填字段
        voucher.setReturned(true);
        voucher.setBusinessType(BusinessType.SALE_RETURN);
        voucher.setVoucher(originSaleVoucher);

        ReflectUtil.copy(originSaleVoucher, voucher, "dept", "company", "partner", "contract");
        voucher.setInventoryMode(voucher.getContract().getCooperation().getInventoryMode());     //设置库存模式
        voucher.setAccountingMethod(voucher.getContract().getCooperation().getAccountingMethod());  // 核算方式

        voucher.setCustomerExpand(retailReturn.getCustomerExpand().getId());
        voucher.setScene(retailReturn.getScene());
        voucher.setOrigin(retailReturn.getId());
        voucher.setOriginBusinessType(retailReturn.getInnerBusinessType());
        voucher.setSource(retailReturn.getId());
        voucher.setSourceBusinessType(retailReturn.getInnerBusinessType());
        if (isSaleCrossIC) {
            voucher.setClassification(VoucherType.CROSS_IC_CROSS_RETURN);
        } else {
            voucher.setClassification(VoucherType.CROSS_IC_RETURN);
        }

        voucher.setVoucherItems(
                originSaleVoucher.getVoucherItems().stream().map(saleItem -> {
                    VoucherItem voucherItem = new VoucherItem();

                    voucherItem.setProduct(saleItem.getProduct());
                    voucherItem.setTax(saleItem.getTax());
                    voucherItem.setOwner(saleItem.obtainOwner());
                    voucherItem.setUom(saleItem.getUom());          // 设置为销售的单位以及数量
                    voucherItem.setProductQty(-1 * Math.abs(saleItem.getProductQty()));
                    voucherItem.setPriceUnit(saleItem.getPriceUnit());      // 默认为退货单价
                    voucherItem.setOriginItemId(retailReturnItem.getId());
                    voucherItem.setSourceItemId(retailReturnItem.getId());
                    voucherItem.setOwner(originSaleVoucher.getCompany());

                    voucherItem.setVoucherItem(saleItem);   // 退回时传入明细行号

                    return voucherItem;
                }).collect(Collectors.toSet()));

        voucher = invoke("voucher.create", MapUtil.mapped(voucher));
        if (voucher.getAmtTotal() != 0) {   // 为 0 的部分不生成
            createFixedOriginNumberInvoice(retailReturn, voucher);
        }
    }

    private void returnPurchaseVoucher(PartyRole partner, RetailReturn retailReturn, RetailReturnItem retailReturnItem, Voucher originSaleVoucher) {
        Voucher voucher = new Voucher();
        voucher.setReturned(true);
        voucher.setBusinessType(BusinessType.PURCHASE_RETURN);

        ReflectUtil.copy(originSaleVoucher, voucher, "dept", "company");

        voucher.setPartner(partner.getParty().getPartyRoleByType("Supplier"));
        voucher.setAccountingMethod(AccountingMethod.AM_PURCHASE);//核算方式
        voucher.setInventoryMode(InventoryMode.IM_OWN);//库存方式

        voucher.setClerk(retailReturn.getClerk());
        voucher.setScene(retailReturn.getScene());
        voucher.setOrigin(retailReturn.getId());
        voucher.setOriginBusinessType(retailReturn.getInnerBusinessType());
        voucher.setSource(retailReturn.getId());
        voucher.setSourceBusinessType(retailReturn.getInnerBusinessType());
        voucher.setCustomerExpand(retailReturn.getCustomerExpand().getId());

        voucher.setVoucherItems(
                originSaleVoucher.getVoucherItems().stream().map(saleItem -> {
                    VoucherItem voucherItem = new VoucherItem();

                    voucherItem.setProduct(saleItem.getProduct());
                    voucherItem.setOwner(saleItem.obtainOwner());
                    voucherItem.setUom(saleItem.getUom());          // 设置为销售的单位以及数量
                    voucherItem.setProductQty(-1 * Math.abs(saleItem.getProductQty()));
                    voucherItem.setOriginItemId(retailReturnItem.getId());
                    voucherItem.setSourceItemId(retailReturnItem.getId());

                    // 获取原销售批次
                    VoucherInventory voucherInventory = SpringManager.getBean(VoucherInventoryRepository.class)
                            .findAll(JpaDsl.toCriteriaByEq("voucher.id", originSaleVoucher.getId(), "voucherItem", saleItem)).stream().findFirst().get();
                    InventoryBatch inventoryBatch = voucherInventory.getInventoryBatch();
                    voucherItem.setInventoryBatch(inventoryBatch);
                    voucherItem.setSupplier(inventoryBatch.getSupplier());
                    voucherItem.setPriceUnit(inventoryBatch.getTaxCostPrice());
                    voucherItem.setTax(inventoryBatch.getTax());

                    //  增加（减少）冻结数量
                    inventoryService.changeFrostQty(inventoryBatch, voucherItem.getUom(), saleItem.getProductQty(), inventoryBatch.getCompany(),
                            retailReturn.getInnerBusinessType(), retailReturn.getId(), retailReturnItem.getId(), "生成零售带安服务商品返厂凭证");

                    return voucherItem;
                }).collect(Collectors.toSet()));

        voucher = invoke("voucher.create", MapUtil.mapped(voucher));

        // 存在为 0 的部分退
        if (voucher.getAmtTotal() != 0) {
            createFixedOriginNumberInvoice(retailReturn, voucher);
        }
    }


    private void createFixedOriginNumberInvoice(RetailReturn retailReturn, Voucher voucher) {
        // 获取 invoice Mapping 文件
        Map m = invoke("voucher.flow.invoice", MapUtil.mapped(voucher));

        m.put("origin", retailReturn.getSaleOrder().getSource());
        m.put("originBusinessType", retailReturn.getSaleOrder().getSourceBusinessType());

        // 生成账单
        invoke("invoice.create", m);
    }

}
